using System;
using System.Runtime.CompilerServices;
using br.odb.liboldfart.wavefront_obj;
using Gtk;
//-----------------------------------------------------------------------------
namespace MonoBED3
{
//-----------------------------------------------------------------------------	
	public class EditorContext
	{
		private World world;
		private Boolean needsCommit;
		private GameObject currentEntity;
		private Gtk.Window parentWindow;
		private Cursor cursor;
		private int sectorId;
		private int actorId;
		private string filename;
		private bool updating;
		ContextListener master;
		
		public World getWorld() {			
			return world;
		}		
		
		public void copyFrom( EditorContext other ) {
			updating = true;
			world.copyFrom( other.world );
			needsCommit = other.needsCommit;
			sectorId = other.sectorId;
			actorId = other.actorId;
			currentEntity = null;
			parentWindow = other.parentWindow;
			filename = other.filename;
			updating = false;
			master = other.master;
		}
		
		public void setBroadcaster( ContextListener cl ) {
			master = cl;
		}
//-----------------------------------------------------------------------------		
		public EditorContext (Gtk.Window parent)
		{
			updating = false;
			world = new World();
			cursor = new Cursor();
			parentWindow = parent;
			Logger.log("------------------ NEW EDITOR CONTEXT CREATED ------------------");			
			needsCommit = false;
			filename = null;
		}		
		public Cursor getCursor()
		{
			return cursor;
		}
		
		public void setCurrentEntityFromCursor() {
			int sector;
			int actor;
			
			actor = world.getActorAt( cursor.getX(), cursor.getY(), cursor.getZ() );
			
			if ( actor != -1 ) {				
				setCurrentActorId( actor );
				return;
			}
			
			sector = world.getSectorAt( cursor.getX(), cursor.getY(), cursor.getZ() );
			
			if ( sector != -1 ) {
				setCurrentSectorId( sector );
				return;
			}
		}
			
		public void setCurrentActorId( int id ) {
			actorId = id;
			currentEntity = world.getActor( id );			
			notifyChange();			
			askForScreenRefresh();
		}
		
		public int getCurrentActorId() {
			return actorId;
		}
		
		public void setCurrentSectorId( int id ) {
			setCurrentSectorId( id, true );
		}
		
		public void setCurrentSectorId( int id, bool shouldNotify ) {
			
			sectorId = id;
			currentEntity = world.getSector( id );

			if ( shouldNotify ) {
				notifyChange();
				askForScreenRefresh();
			}
		}
		
		public int getCurrentSectorId() {
			return sectorId;
		}
		
		public GameObjectFacade getCurrentEntityFacade()
		{
			if ( currentEntity != null )
				return (GameObjectFacade)currentEntity.getConnection();
			else
				return null;
			
		}
//-----------------------------------------------------------------------------
		public SectorFacade addNewSector()
		{
			return addNewSector( true );
		}
		
		public SectorFacade addNewSector( bool shouldNotify )
		{
			SectorFacade facade = null;			 
			currentEntity = world.addNewSector();
			facade = ((Sector)currentEntity).getConnection();	
			( ( Sector ) currentEntity ).setIsParent( true );
			
			if ( shouldNotify )
				notifyChange();
			
			return facade;
		}
//-----------------------------------------------------------------------------
		public ActorFacade addNewActor()
		{
			return addNewActor( true );
		}	
		
		public ActorFacade addNewActor( bool shouldNotify )
		{
			ActorFacade facade = null;
			currentEntity = world.addNewActor();
			facade = (ActorFacade)((Actor)currentEntity).getConnection();
			
			if ( shouldNotify )
				notifyChange();
			
			return facade;
		}		
//-----------------------------------------------------------------------------		
		public FacadeConnection addNewEntity(EntityKind kind)
		{				
			return addNewEntity( kind, true );
		}
		
		public FacadeConnection addNewEntity(EntityKind kind, bool shouldNotify )
		{	
			
			FacadeConnection facade = null;
			
			switch (kind)
			{
			case EntityKind.SECTOR:

				facade = addNewSector( shouldNotify );
				setCurrentSectorId( ( facade.getObject() as GameObject ) .getId(), shouldNotify );
			break;
			case EntityKind.ACTOR:
				facade = addNewActor( shouldNotify );
			break;				
			}
			
			if (currentEntity != null && getCursor() != null)	{
				
				currentEntity.moveTo( getCursor().getX(), getCursor().getY(),getCursor().getZ());
			}			
			
			needsCommit = true;
			notifyChange();
			
			return facade;
		}
//-----------------------------------------------------------------------------		
		public bool isCommitNeeded()
		{
			return needsCommit;			
		}
//-----------------------------------------------------------------------------		
		public void commit()
		{
			needsCommit = false;
		}
//-----------------------------------------------------------------------------		
		public ActorFacade getActorFacade(int index)
		{
			if (world != null)
			{
				Actor actor = world.getActor(index);
				if (actor != null)
					return (ActorFacade)actor.getConnection();
			}
			
			return null;
		}
//-----------------------------------------------------------------------------		
		public SectorFacade getSectorFacade(int index)
		{
			if (world != null)
			{
				Sector sector = world.getSector(index);
				if (sector != null)
					return sector.getConnection();
			}
		
			return null;
		}		
		
		public int getTotalSectors() {
			return world.getTotalSectors();
		}
		
		public int getTotalActors() {
			return world.getTotalActors();
		}
		
//-----------------------------------------------------------------------------	
		
		public void importBZK2( String path, bool ignoreNonLeafs ) {
			
			world.eraseAll();
			filename = path;
			BZK2Helper helper = new BZK2Helper();
			helper.load( path );
			Sector s;
			Sector s2;
			SectorFacade s3;
			
			Logger.log("------carregado------");
			
			for ( int c = 0; c < helper.getTotalSectors(); ++c )  {
				
				if ( c == 0 && ignoreNonLeafs )
					continue;
				
				s = helper.getSector( c );
				
				if ( s.isParent() || !ignoreNonLeafs ) {
					s3 = ( SectorFacade ) addNewEntity( EntityKind.SECTOR, false );
					s2 = ( ( Sector ) s3.getObject() );
					
					s2.moveTo( s.getX(), s.getY(), s.getZ() );
					s2.setDX( s.getDX() );
					s2.setDY( s.getDY() );
					s2.setDZ( s.getDZ() );
					
					for ( int d = 0; d < 6; ++d ) {
						
						s2.setLink( d, s.getLink( d ) );
						s2.setColor( d, new Color( s.getColor( d ) ) );
 					}					
				}
			}
			
			this.notifyChange();
		}
		
		public void loadSnapshot( String path, bool ignoreNonLeafs ) {
			filename = path;
			java.util.ArrayList list = new java.util.ArrayList();
			java.io.FileInputStream fis = new java.io.FileInputStream( path );			
			br.odb.libscene.World w = new br.odb.libscene.World();
			w.internalize( fis, list, false );
			internalize( w, ignoreNonLeafs );
			this.notifyChange();
		}
		
		public void internalize( br.odb.libscene.World w, bool ignoreNonLeafs ) {
			internalize( w, ignoreNonLeafs, false );
		}
		
		public void internalize( br.odb.libscene.World w, bool ignoreNonLeafs, bool ignoreFistSector ) {

			br.odb.libscene.Sector dllSector;
			SectorFacade sector;
			world.eraseAll();
			
			for ( int c = 0; c < w.getTotalSectors(); ++c)  {
				
				if ( c == 0 && ignoreFistSector )
					continue;
				
				dllSector = w.getSector( c );
				
				if ( !dllSector.isMaster() && ignoreNonLeafs ) 
					continue;
				
				
				
				sector = ( SectorFacade ) addNewEntity( EntityKind.SECTOR, false );
				( ( Sector )sector.getObject() ).initFrom( dllSector );
			}
			needsCommit = false;
		}

//-----------------------------------------------------------------------------	
		public void askForScreenRefresh()
		{
			parentWindow.QueueDraw();
		}
		
		public void notifyChange() {
			
			if ( isLocked() )
				return;
			
			lockContext();
			
	//		needsCommit = true;
			
			if ( master != null )
				master.contextModified();			
			
			unlockContext();
		}
		
		[MethodImpl(MethodImplOptions.Synchronized)]
		public void lockContext() {
			updating = true;
		}
		
		[MethodImpl(MethodImplOptions.Synchronized)]
		public void unlockContext() {
			updating = false;
		}		
		
		[MethodImpl(MethodImplOptions.Synchronized)]
		public bool isLocked() {
			
			return updating;
		}
		
		public void saveCurrent() {
			save( filename );
		}
		
		public string getFilename() {
			return filename;
		}
		
		public void removeEntity( Sector s ) {
			this.world.removeSector( s );
		}

		public void removeEntity( Actor a ) {
			this.world.removeActor( a );
		}
		
		
		public void exportSectorAsObjTo( Sector sector, String path ) {

			String obj = WavefrontOBJExporter.getWavefrontFor( sector.makeBZK3Sector() );
			System.IO.TextWriter tw = new System.IO.StreamWriter( path );
			tw.Write( obj );
			tw.Close();
		}
		
		public void save( String path ) {
			
			if ( filename == null || filename == "" )
				filename = path;
			
			System.IO.TextWriter tw = new System.IO.StreamWriter( path );
			tw.Write( world.ToString() );
			tw.Close();
			needsCommit = false;
		}
	}
}
//-----------------------------------------------------------------------------